/*******************************************************************************
 * Copyright (c) 2008 CEA LIST.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA LIST - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.classdiagram.tabbedproperties.section;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.properties.tabbed.AbstractPropertySection;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.common.edit.command.ChangeCommand;
import org.eclipse.uml2.common.util.CacheAdapter;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralNull;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.OpaqueExpression;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.ValueSpecification;

import com.cea.papyrus.core.commands.EMFtoGEFWrapCommand;
import com.cea.papyrus.core.editor.CommandStackUtils;
import com.cea.papyrus.core.tabbedproperties.PropertyViewSection;
import com.cea.papyrus.diagram.classdiagram.tabbedproperties.composite.SmallOpaqueExpressionComposite;
import com.cea.papyrus.umlutils.ValueSpecificationUtil;

/**
 * 
 */
public class ValueSpecificationSection extends PropertyViewSection {

	/** key for data in the menu for Value Specification Kind choice button*/
	protected static final String VALUE_SPEC_DATA = "value_spec_data";

	/** Combo to choose the kind of valueSpecification to use for default value */
	protected Button specificationCombo;

	/** label displaying a warning if necessary */
	protected CLabel validationLabel;

	/** kind of the class that implements the default value */
	protected ValueSpecificationKind valueSpecificationType;

	/** Composite which is the editor of the default value */ 
	protected Composite defaultValueComposite;

	/** composite that holds the default value sets of controls */
	protected Composite defaultValueControlsComposite;

	/** Input validator for the default value editor */
	protected IInputValidator inputValidator;

	/** Warning image for validation label */
	protected final Image WARNING_IMAGE = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK);

	/** Menu for the value specification type choice button */
	protected Menu menu;

	/** Text zone for integer/UnlimitedNatural, String default value */
	protected Text defaultValueText;

	/** Composite for empty default value area (LiteralNull and no default value */
	protected Composite emptyComposite;

	/** Text zone for boolean default value */
	protected CCombo booleanCombo;

	/** stack layout for the default value composite */
	protected StackLayout stackLayout;

	/** listener for the combo for true/false value */
	protected SelectionListener comboListener;

	/** Focus listener for the text area for the default value */
	protected FocusListener focusListener;

	/** Modify listener for the text area for the default value */
	protected ModifyListener textModifyListener;

	/** Key listener for 'Enter' when editing the text default area */
	protected EnterKeyListener textKeyListener;

	/** Combo for opaque expression edition */
	protected SmallOpaqueExpressionComposite opaqueExpressionComposite;

	/** instance of the value specification */
	protected ValueSpecification valueSpecification;

	/**
	 * Creates a new ValueSpecificationSection. 
	 */
	public ValueSpecificationSection() {
		opaqueExpressionComposite = new SmallOpaqueExpressionComposite();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);

		defaultValueControlsComposite = getWidgetFactory().createComposite(parent);
		FormLayout layout = new FormLayout();
		layout.marginWidth = ITabbedPropertyConstants.HSPACE + 2;
		layout.marginHeight = ITabbedPropertyConstants.VSPACE;
		layout.spacing = 1;
		defaultValueControlsComposite.setLayout(layout);

		validationLabel = getWidgetFactory().createCLabel(defaultValueControlsComposite, "");
		// data = new FormData(500, SWT.DEFAULT);

		FormData data = new FormData(SWT.DEFAULT, 15);
		data.left = new FormAttachment(0, ITabbedPropertyConstants.HSPACE);
		data.right = new FormAttachment(100, -ITabbedPropertyConstants.HSPACE);
		data.bottom = new FormAttachment(100, 0);
		validationLabel.setLayoutData(data);

		CLabel label = getWidgetFactory().createCLabel(defaultValueControlsComposite, "Default Value:"); 
		data = new FormData(SWT.DEFAULT, 15);
		data.left = new FormAttachment(0, 0);
		data.top = new FormAttachment(0, 0);
		data.bottom = new FormAttachment(validationLabel);
		label.setLayoutData(data);

		specificationCombo = getWidgetFactory().createButton(defaultValueControlsComposite, "", SWT.NONE);
		data = new FormData(130, SWT.DEFAULT);
		data.left = new FormAttachment(0, AbstractPropertySection.STANDARD_LABEL_WIDTH+ITabbedPropertyConstants.HSPACE);
		data.top = new FormAttachment(0, 0);
		data.bottom = new FormAttachment(validationLabel);
		specificationCombo.setLayoutData(data);

		defaultValueComposite = getWidgetFactory().createComposite(defaultValueControlsComposite, SWT.NONE);
		stackLayout = new StackLayout();
		defaultValueComposite.setLayout(stackLayout);
		data = new FormData(SWT.DEFAULT, 15);
		data.left = new FormAttachment(specificationCombo, ITabbedPropertyConstants.HSPACE);
		data.top = new FormAttachment(0, 0);
		data.right = new FormAttachment(100, -ITabbedPropertyConstants.HSPACE);
		data.bottom = new FormAttachment(validationLabel);
		defaultValueComposite.setLayoutData(data);

		emptyComposite = getWidgetFactory().createComposite(defaultValueComposite, SWT.NONE);

		defaultValueText = getWidgetFactory().createText(defaultValueComposite, "", SWT.BORDER);
		focusListener = new TextFocusListener();
		defaultValueText.addFocusListener(focusListener);
		textModifyListener = new TextModifyListener();
		defaultValueText.addModifyListener(textModifyListener);
		textKeyListener = new EnterKeyListener();
		defaultValueText.addKeyListener(textKeyListener);

		booleanCombo = getWidgetFactory().createCCombo(defaultValueComposite, SWT.READ_ONLY | SWT.BORDER);
		booleanCombo.setItems(new String[] { "false", "true" });
		// add listener to combo
		comboListener = new TrueFalseSelectionListener();
		booleanCombo.addSelectionListener(comboListener);

		opaqueExpressionComposite.createControls(defaultValueComposite, tabbedPropertySheetPage);
		opaqueExpressionComposite.setErrorLabel(validationLabel);

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void dispose() {
		opaqueExpressionComposite.dispose();
		if(booleanCombo !=null && !booleanCombo.isDisposed()) {
			booleanCombo.removeSelectionListener(comboListener);
		}
		if(defaultValueText !=null && !defaultValueText.isDisposed()) {
			defaultValueText.removeFocusListener(focusListener);
			defaultValueText.removeModifyListener(textModifyListener);
			defaultValueText.removeKeyListener(textKeyListener);
		}
		opaqueExpressionComposite.dispose();
		super.dispose();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void refresh() {
		super.refresh();
		if(!specificationCombo.isDisposed()){
			// refresh the menu  (the label provider is now available)
			if(menu==null || !menu.isDisposed()) {
				createMenuForValueSpecificationChoiceButton();
			}

			// change the text composite or its validator, depending on the implementation of the default value
			// retrieve type of element (element is property or parameter)
			valueSpecificationType = getValueSpecificationKind();

			switch(valueSpecificationType) {
			case NONE:
				specificationCombo.setText(ValueSpecificationKind.NONE.getName());
				refreshDefaultValueEditor();
				specificationCombo.setImage(null);
				break;
			case LITERAL_STRING:
				specificationCombo.setText(ValueSpecificationKind.LITERAL_STRING.getName());
				refreshDefaultValueEditor(((LiteralString)getValueSpecification()));
				specificationCombo.setImage(getLabelProvider().getImage(getValueSpecification()));
				break;
			case LITERAL_BOOLEAN:
				specificationCombo.setText(ValueSpecificationKind.LITERAL_BOOLEAN.getName());
				refreshDefaultValueEditor(((LiteralBoolean)getValueSpecification()));
				specificationCombo.setImage(labelProvider.getImage(getValueSpecification()));
				break;
			case LITERAL_INTEGER:
				specificationCombo.setText(ValueSpecificationKind.LITERAL_INTEGER.getName());
				refreshDefaultValueEditor(((LiteralInteger)getValueSpecification()));
				specificationCombo.setImage(labelProvider.getImage(getValueSpecification()));
				break;
			case LITERAL_UNLIMITED_NATURAL:
				specificationCombo.setText(ValueSpecificationKind.LITERAL_UNLIMITED_NATURAL.getName());
				refreshDefaultValueEditor(((LiteralUnlimitedNatural)getValueSpecification()));
				specificationCombo.setImage(labelProvider.getImage(getValueSpecification()));
				break;
			case OPAQUE_EXPRESSION:
				specificationCombo.setText(ValueSpecificationKind.OPAQUE_EXPRESSION.getName());
				refreshDefaultValueEditor(((OpaqueExpression)getValueSpecification()));
				specificationCombo.setImage(labelProvider.getImage(getValueSpecification()));
				break;
			case LITERAL_NULL:
				specificationCombo.setText(ValueSpecificationKind.LITERAL_NULL.getName());
				refreshDefaultValueEditor(((LiteralNull)getValueSpecification()));
				specificationCombo.setImage(labelProvider.getImage(getValueSpecification()));
				break;
			default: {
				specificationCombo.setText(ValueSpecificationKind.NONE.getName());
				refreshDefaultValueEditor();
				specificationCombo.setImage(null);
				break;}
			}
		}
	}

	/**
	 * Adds the menu to the Value Specification choice button
	 */
	protected void createMenuForValueSpecificationChoiceButton() {
		SpecificationTypeSelectionListener selectionTypelistener = new SpecificationTypeSelectionListener();
		menu = new Menu(specificationCombo);
		menu.setEnabled(true) ;
		for (ValueSpecificationKind valueSpecKind : ValueSpecificationKind.values()) {
			if(checkValueSpecificationConstraint(valueSpecKind)) {
				MenuItem item = new MenuItem(menu, SWT.BORDER);
				if(valueSpecKind.getMetaclass() != null) {
					if(labelProvider!=null) {
						item.setImage(labelProvider.getImage(valueSpecKind.getMetaclass()));
					}
				} else {
					item.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE));
				}
				item.setText(valueSpecKind.getName());
				item.setData(VALUE_SPEC_DATA, valueSpecKind);
				item.addSelectionListener(selectionTypelistener);
			}
		}

		specificationCombo.addSelectionListener(new SelectionListener() {

			/**
			 * {@inheritDoc}
			 */
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			/**
			 * {@inheritDoc}
			 */
			public void widgetSelected(SelectionEvent e) {
				menu.setVisible(true);	
			}

		});
	}

	/**
	 * Check if the value specification is available for the type of element
	 * @param valueSpecKind the value specification to check
	 * @return <code>true</code> if this kind of ValueSpecification can be used for this type of element
	 */
	protected boolean checkValueSpecificationConstraint(ValueSpecificationKind valueSpecKind) {
		return true;
	}

	/**
	 * Retrieve the type of the ValueSpecification that defines the default 
	 * value associated to the selected UML element, or <code>0</code> if 
	 * no value specification is given for the element. 
	 * @return the ValueSpecification that represents the default value or 
	 * <code>null</code> if no value specification exists
	 */
	protected ValueSpecificationKind getValueSpecificationKind() {
		if(getValueSpecification()!=null) {
			return ValueSpecificationKind.getByMetaclassID(getValueSpecification().eClass().getClassifierID());
		}
		return ValueSpecificationKind.NONE;
	}

	/**
	 * Removes the composite that defines the default value editor 
	 */
	protected void refreshDefaultValueEditor() {
		stackLayout.topControl = emptyComposite;
		defaultValueComposite.layout();
		setInputValidator(null);
	}

	/**
	 * Refresh the composite that defines the default value editor 
	 * @param defaultValueSpecification the default string value to display
	 */
	protected void refreshDefaultValueEditor(LiteralString defaultValueSpecification) {
		// sets the editor to be a standard editor, with no verification
		stackLayout.topControl = defaultValueText;
		defaultValueComposite.layout();

		String value = defaultValueSpecification.getValue();
		defaultValueText.setText((value != null) ? value : "");

		// update validator
		setInputValidator(null);
	}

	/**
	 * Refresh the composite that defines the default value editor 
	 * @param defaultValueSpecification the default null value to display
	 */
	protected void refreshDefaultValueEditor(LiteralNull defaultValueSpecification) {
		// sets the editor to be not an editor (no value => null)
		stackLayout.topControl = emptyComposite;
		defaultValueComposite.layout();
		// update validator
		setInputValidator(null);
	}

	/**
	 * Refresh the composite that defines the default value editor 
	 * @param defaultValueSpecification the default string value to display
	 */
	protected void refreshDefaultValueEditor(LiteralUnlimitedNatural defaultValueSpecification) {
		// sets the editor to be a standard editor, with unlimited natural verification
		stackLayout.topControl = defaultValueText;
		defaultValueComposite.layout();

		int value = defaultValueSpecification.unlimitedValue();
		defaultValueText.setText(Integer.toString(value));
		// update validator
		setInputValidator(new IInputValidator() {
			/**
			 * {@inheritDoc}
			 */
			public String isValid(String newText) {
				if(newText==null) {
					return "";
				}
				try {
					if("*".equals(newText.trim())) {
						return "";
					} else {
						Integer.parseInt(newText);
					}
				} catch (NumberFormatException e) {
					return "Please enter a valid unlimited natural, or change the type of the defaut Value ValueSpecification";
				}
				return "";
			}
		});
	}

	/**
	 * Refresh the composite that defines the default value editor 
	 * @param defaultValueSpecification the default string value to display
	 */
	protected void refreshDefaultValueEditor(OpaqueExpression defaultValueSpecification) {
		// sets the editor to be an advanced editor
		stackLayout.topControl = opaqueExpressionComposite.getMainComposite();
		opaqueExpressionComposite.setOpaqueExpression(defaultValueSpecification);
		opaqueExpressionComposite.refresh();
		defaultValueComposite.layout();

		// update validator
		setInputValidator(null);
	}

	/**
	 * Refresh the composite that defines the default value editor 
	 * @param defaultValueSpecification the default boolean value to display
	 */
	protected void refreshDefaultValueEditor(LiteralBoolean defaultValueSpecification) {
		// sets the editor to be a combo with true/false
		stackLayout.topControl = booleanCombo;
		defaultValueComposite.layout();
		if(defaultValueSpecification.isValue()) {
			booleanCombo.select(1);
		} else {
			booleanCombo.select(0);
		}

		// update validator
		setErrorMessage("");
		setInputValidator(null);
	}

	/**
	 * Refresh the composite that defines the default value editor 
	 * @param defaultValueSpecification the default integer value to display
	 */
	protected void refreshDefaultValueEditor(LiteralInteger defaultValueSpecification) {
		// sets the editor to be a standard editor, with integer verification
		stackLayout.topControl = defaultValueText;
		defaultValueComposite.layout();

		int value = defaultValueSpecification.integerValue();
		defaultValueText.setText(Integer.toString(value));

		// update validator
		setInputValidator(new IInputValidator() {
			/**
			 * {@inheritDoc}
			 */
			public String isValid(String newText) {
				try {
					Integer.parseInt(newText);
				} catch (NumberFormatException e) {
					return "Please enter a valid integer, or change the type of the defaut Value ValueSpecification";
				}
				return "";
			}
		});
	}

	/**
	 * Sets the new Error Message to display
	 * @param string the error message
	 */
	protected void setErrorMessage(String string) {
		validationLabel.setText(string);
		if(string == null || "".equals(string)) {
			validationLabel.setImage(null);
		} else {
			validationLabel.setImage(WARNING_IMAGE);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void selectionChanged(ISelection selection) {
		super.selectionChanged(selection);
		opaqueExpressionComposite.selectionChanged(selection);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setInput(IWorkbenchPart part, ISelection selection) {
		super.setInput(part, selection);
		opaqueExpressionComposite.setInput(part, selection);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void aboutToBeHidden() {
		super.aboutToBeHidden();
		opaqueExpressionComposite.aboutToBeHidden();
	}

	/**
	 * Returns the input validator for the default value editor
	 * @return the input validator for the default value editor
	 */
	public IInputValidator getInputValidator() {
		return inputValidator;
	}

	/**
	 * Sets the input validator for the default value editor
	 * @param inputValidator the inputValidator to set
	 */
	public void setInputValidator(IInputValidator inputValidator) {
		this.inputValidator = inputValidator;
	}

	/**
	 * Returns the current selected value specification
	 * @return the current selected value specification
	 */
	public ValueSpecification getValueSpecification() {
		return valueSpecification;
	}

	/**
	 * Sets the current selected value specification
	 * @param valueSpecification the new selected value specification
	 */
	public void setValueSpecification(ValueSpecification valueSpecification) {
		this.valueSpecification = valueSpecification;
	}

	/**
	 * Adds the new ValueSpecification as a default value to the container
	 * @param container the container which has the newSpecif as default value
	 * @param newSpecif the new ValueSpecification of the container
	 */
	protected void addNewSpecification(Element container, ValueSpecification newSpecif) {
		// do nothing.
		// should be overridden when using in collaboration with another section (ex: default value of property)
	}

	/**
	 * Listener for the CCombo selection composite, to change the default value implementation
	 */
	protected class SpecificationTypeSelectionListener implements SelectionListener {

		/**
		 * {@inheritDoc}
		 */
		public void widgetDefaultSelected(SelectionEvent e) {
		}

		/**
		 * {@inheritDoc}
		 */
		public void widgetSelected(SelectionEvent e) {
			// retrieve the value specification
			final ValueSpecificationKind valueSpecKind = (ValueSpecificationKind)((MenuItem)e.widget).getData(VALUE_SPEC_DATA);

			final AdapterFactoryEditingDomain emfDomain = getModelManager().getDiResourceSet().getEditingDomain();
			EMFtoGEFWrapCommand command = new EMFtoGEFWrapCommand(emfDomain) {
				@Override
				public org.eclipse.emf.common.command.Command createEMFCommand() {
					return new ChangeCommand(emfDomain, new Runnable() {
						public void run() {
							// remove previous implementation (must keep the adapters)
							//1. retrieve the previous specification and its adapters
							ValueSpecification specification = getValueSpecification();
							// owner of the default Value
							Element container = (Element)getElement() ;

							String previousValue = "";

							List<Adapter> adapters = new ArrayList<Adapter>();
							//2. save previous information
							if(specification!=null) {
								//save previous value, if exists
								previousValue = specification.stringValue();

								Iterator<Adapter> it = specification.eAdapters().iterator();
								while(it.hasNext()) {
									Adapter adapter  = it.next();
									if(!(adapter instanceof CacheAdapter)) {
										adapters.add(adapter);
									}
								}

								//2. remove adapters
								specification.eAdapters().removeAll(adapters);
							}

							//3. crates the new Value specification, according to the selection
							// creates the new one if one exists
							if(!ValueSpecificationKind.NONE.equals(valueSpecKind)) {	// does not treat NONE, as nothing can be created
								// creates the default value
								ValueSpecification newSpecif = (ValueSpecification)UMLFactory.eINSTANCE.create(valueSpecKind.getMetaclass());

								ValueSpecificationUtil.restoreSpecificationValue(newSpecif, previousValue);

								addNewSpecification(container, newSpecif);
								// restore adapters
								if(adapters!=null) {
									newSpecif.eAdapters().addAll(adapters);
								}
							}
							else {
								// delete previous Specification
								specification.destroy();
							}
						}

					}, "Change Default Value Implementation", "Changes the element that defines the Default Value");
				}
			};
			CommandStackUtils.getCommandStack().execute(command);
			refresh();
		}
	}

	/**
	 * Listener for the True/False value combo composite 
	 */
	protected class TrueFalseSelectionListener implements SelectionListener {

		/**
		 * {@inheritDoc}
		 */
		public void widgetDefaultSelected(SelectionEvent e) {
		}

		/**
		 * {@inheritDoc}
		 */
		public void widgetSelected(SelectionEvent e) {
			final int selectionIndex = ((CCombo)e.widget).getSelectionIndex();

			final AdapterFactoryEditingDomain emfDomain = getModelManager().getDiResourceSet().getEditingDomain();
			EMFtoGEFWrapCommand command = new EMFtoGEFWrapCommand(emfDomain) {
				@Override
				public org.eclipse.emf.common.command.Command createEMFCommand() {
					return new ChangeCommand(emfDomain, new Runnable() {
						public void run() {
							//1. retrieve the specification 
							LiteralBoolean specification = (LiteralBoolean)getValueSpecification();

							//2. change value
							if(selectionIndex == 0) {	// false
								specification.setValue(false);
							} else if(selectionIndex == 1) { // true
								specification.setValue(true);
							}

						}
					}, "Change Boolean default value", "Changes the default value");
				}
			};
			CommandStackUtils.getCommandStack().execute(command);
			refresh();
		}
	}

	/**
	 * Listener for the text area. If focus is lost, it applies the modifications to the element
	 */
	protected class TextFocusListener implements FocusListener {

		/**
		 * {@inheritDoc}
		 */
		public void focusGained(FocusEvent e) {

		}
		/**
		 * {@inheritDoc}
		 */
		public void focusLost(FocusEvent e) {
			// get the new value
			final String text = ( ((Text)e.widget).getText() != null ) ? ((Text)e.widget).getText().trim() : null;
			if(text == null) {
				// should never happened
				return;
			}
			applyNewTextValue(text);
			refresh();
		}
	}

	/**
	 * Listener for the text area for validation
	 */
	protected class TextModifyListener implements ModifyListener {

		public void modifyText(ModifyEvent e) {
			String text = ((Text)e.widget).getText();
			if(text ==null) {
				return;
			}
			if(inputValidator!=null) {
				setErrorMessage(inputValidator.isValid(text));
			}
		}
	}

	/**
	 * Key listener for the "enter" event
	 */
	protected class EnterKeyListener implements KeyListener {

		/**
		 * {@inheritDoc}
		 */
		public void keyPressed(KeyEvent e) {

		}

		/**
		 * {@inheritDoc}
		 */
		public void keyReleased(KeyEvent e) {
			// do nothing
			if(SWT.CR==e.keyCode) {
				applyNewTextValue(((Text)e.widget).getText());
				// lose focus
				defaultValueControlsComposite.setFocus();
			}
		}
	}

	/**
	 * Applies to a literal specification the specified value 
	 * @param text the new text value of the literal specification
	 */
	protected void applyNewTextValue(final String text) {
		final AdapterFactoryEditingDomain emfDomain = getModelManager().getDiResourceSet().getEditingDomain();
		EMFtoGEFWrapCommand command = new EMFtoGEFWrapCommand(emfDomain) {
			@Override
			public org.eclipse.emf.common.command.Command createEMFCommand() {
				return new ChangeCommand(emfDomain, new Runnable() {
					public void run() {
						//1. retrieve the kind of specification (Literal String, Literal integer, Literal Unlimited)
						ValueSpecification spec = getValueSpecification();
						switch (spec.eClass().getClassifierID()) {
						case UMLPackage.LITERAL_STRING:
							((LiteralString)spec).setValue(text);
							break;
						case UMLPackage.LITERAL_INTEGER:
							// try to get integer value
							try {
								int value = Integer.parseInt(text);
								((LiteralInteger)spec).setValue(value);
							} catch (NumberFormatException e) {
								// impossible to get the value
							}
							break;
						case UMLPackage.LITERAL_UNLIMITED_NATURAL:
							// try to get integer value
							try {
								int value;
								if("*".equals(text)) {
									value = -1;
								} else {
									value = Integer.parseInt(text);
								}
								((LiteralUnlimitedNatural)spec).setValue(value);
							} catch (NumberFormatException e) {
								// impossible to get the value
							}
							break;
						}
					}
				}, "Change Boolean default value", "Changes the default value");
			}
		};
		CommandStackUtils.getCommandStack().execute(command);
	}

}
